package 集合;
//Java基础之Comparable与Comparator
//一、前言：
//Java中实现对对象的排序一般情况下主要有以下两种实现方式（万物皆对象嘛）：
//  -对象所在的类实现Comparable 接口
//  -定义比较器，实现Comparator接口。
//
//二、Comparable介绍：
//  -Comparable是在集合内部定义的方法实现的排序，位于java.lang包下：
//  -Comparable只有一个方法：
// package java.lang;
// import java.util.*;
// 
// public interface Comparable<T> {
//     public int compareTo(T o);
// }
//  -若x.compareTo(y) <0，则x<y;若x.compareTo(y) =0，则x=y;若x.compareTo(y) >0，则x=y;
//  -Comparable是一个对象，本身就已经支持自比较所需要实现的接口。
//  -自定义类要在加入list容器中后能够排序，也可以实现Comparable接口。
//  -在用Collections类的sort方法排序时若不指定Comparator，那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
//  -若一个类实现了comparable接口，则意味着该类支持排序。如String、Integer自己就实现了Comparable接口，可完成比较大小操作。
//  -一个已经实现comparable的类的对象或数据，可以通过Collections.sort(list) 或者Arrays.sort(arr)实现排序。
//   通过Collections.sort(list,Collections.reverseOrder());对list进行倒序列。
//
//三、Comparator介绍：
//  -Comparator是在集合外部实现的排序，位于java.util下。
//  -在jdk1.8之前Comparator接口包含了两个方法。
// package java.util;  
// public interface Comparator<T> {  
//       
//      int compare(T o1, T o2);  
//      boolean equals(Object obj);  
// }  
//  -我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么，我们可以新建一个该类的比较器来进行排序。这个比较器只需要
//   实现comparator即可。
//  -如果引用的为第三方jar包，这时候，没办法改变类本身，就可以采用这种方式。
//  -Comparator是一个专用的比较器，当这个对象不支持自比较或者自比较函数不能满足要求时，可写一个比较器来完成两个对象之间大小的比较。
//  -Comparator体现了一种策略模式(strategy design pattern)，就是不改变对象自身，而用一个策略对象(strategy object)来改变它的行为。
//四、二者区别：
//  -Comparable & Comparator 都是用来实现集合中元素的比较、排序的，只是 Comparable 是在集合内部定义的方法实现的排序，Comparator 是
//   在集合外部实现的排序，所以，如想实现排序，就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
//  -Comparator位于包java.util下，而Comparable位于包java.lang下
//  -Comparable 是一个对象本身就已经支持自比较所需要实现的接口（如 String、Integer 自己就可以完成比较大小操作，已经实现Comparable接口）  
//  -自定义的类要在加入list容器中后能够排序，可以实现Comparable接口，在用Collections类的sort方法排序时，如果不指定Comparator，那么就以自
//   然顺序排序，如API所说：Sorts the specified list into ascending order, according to the natural ordering of its 
//   elements. All elements in the list must implement the Comparable interface这里的自然顺序就是实现Comparable接口设定
//   的排序方式。
//  -而 Comparator 是一个专用的比较器，当这个对象不支持自比较或者自比较函数不能满足你的要求时，你可以写一个比较器来完成两个对象之间大小的比较。
//  -可以说一个是自已完成比较，一个是外部程序实现比较的差别而已。
//  -用 Comparator 是策略模式（strategy design pattern），就是不改变对象自身，而用一个策略对象（strategy object）来改变它的行为。
//  -比如：你想对整数采用绝对值大小来排序，Integer 是不符合要求的，你不需要去修改 Integer 类（实际上你也不能这么做）去改变它的排序行为，只要
//   使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。
//五、总结：
//  -Comparable 是排序接口；若一个类实现了 Comparable 接口，就意味着 “该类支持排序”。而 Comparator 是比较器；我们若需要控制某个类的次序，
//   可以建立一个 “该类的比较器” 来进行排序。
//  -前者应该比较固定，和一个具体类相绑定，而后者比较灵活，它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”，而后者可以 “动态绑定”。
//  -我们不难发现：Comparable 相当于 “内部比较器”，而 Comparator 相当于 “外部比较器”


//Java 解惑：Comparable 和 Comparator 的区别
//
//Java 中为我们提供了两种比较机制：Comparable 和 Comparator，他们之间有什么区别呢？今天来了解一下。
//
//Comparable 自然排序
//Comparable 在 java.lang 包下，是一个接口，内部只有一个方法 compareTo()：
//
//public interface Comparable<T> {
//    public int compareTo(T o);
//}
//Comparable 可以让实现它的类的对象进行比较，具体的比较规则是按照 compareTo 方法中的规则进行。这种顺序称为 自然顺序。
//
//compareTo 方法的返回值有三种情况：
//
//e1.compareTo(e2) > 0 即 e1 > e2
//e1.compareTo(e2) = 0 即 e1 = e2
//e1.compareTo(e2) < 0 即 e1 < e2
//注意：
//
//1.由于 null 不是一个类，也不是一个对象，因此在重写 compareTo 方法时应该注意 e.compareTo(null) 的情况，即使 e.equals(null) 返回 false，compareTo 方法也应该主动抛出一个空指针异常 NullPointerException。
//
//2.Comparable 实现类重写 compareTo 方法时一般要求 e1.compareTo(e2) == 0 的结果要和 e1.equals(e2) 一致。这样将来使用 SortedSet 等根据类的自然排序进行排序的集合容器时可以保证保存的数据的顺序和想象中一致。
//
//有人可能好奇上面的第二点如果违反了会怎样呢？
//
//举个例子，如果你往一个 SortedSet 中先后添加两个对象 a 和 b，a b 满足 (!a.equals(b) && a.compareTo(b) == 0)，同时也没有另外指定个 Comparator，那当你添加完 a 再添加 b 时会添加失败返回 false, SortedSet 的 size 也不会增加，因为在 SortedSet 看来它们是相同的，而 SortedSet 中是不允许重复的。
//
//实际上所有实现了 Comparable 接口的 Java 核心类的结果都和 equlas 方法保持一致。
//实现了 Comparable 接口的 List 或则数组可以使用 Collections.sort() 或者 Arrays.sort() 方法进行排序。
//
//实现了 Comparable 接口的对象才能够直接被用作 SortedMap (SortedSet) 的 key，要不然得在外边指定 Comparator 排序规则。
//
//因此自己定义的类如果想要使用有序的集合类，需要实现 Comparable 接口，比如：
//
//**
// * description: 测试用的实体类 书, 实现了 Comparable 接口，自然排序
// * <br/>
// * author: shixinzhang
// * <br/>
// * data: 10/5/2016
// */
//public class BookBean implements Serializable, Comparable {
//    private String name;
//    private int count;
//
//
//    public BookBean(String name, int count) {
//        this.name = name;
//        this.count = count;
//    }
//
//    public String getName() {
//        return name;
//    }
//
//    public void setName(String name) {
//        this.name = name;
//    }
//
//    public int getCount() {
//        return count;
//    }
//
//    public void setCount(int count) {
//        this.count = count;
//    }
//
//    /**
//     * 重写 equals
//     * @param o
//     * @return
//     */
//    @Override
//    public boolean equals(Object o) {
//        if (this == o) return true;
//        if (!(o instanceof BookBean)) return false;
//
//        BookBean bean = (BookBean) o;
//
//        if (getCount() != bean.getCount()) return false;
//        return getName().equals(bean.getName());
//
//    }
//
//    /**
//     * 重写 hashCode 的计算方法
//     * 根据所有属性进行 迭代计算，避免重复
//     * 计算 hashCode 时 计算因子 31 见得很多，是一个质数，不能再被除
//     * @return
//     */
//    @Override
//    public int hashCode() {
//        //调用 String 的 hashCode(), 唯一表示一个字符串内容
//        int result = getName().hashCode();
//        //乘以 31, 再加上 count
//        result = 31 * result + getCount();
//        return result;
//    }
//
//    @Override
//    public String toString() {
//        return "BookBean{" +
//                "name='" + name + '\'' +
//                ", count=" + count +
//                '}';
//    }
//
//    /**
//     * 当向 TreeSet 中添加 BookBean 时，会调用这个方法进行排序
//     * @param another
//     * @return
//     */
//    @Override
//    public int compareTo(Object another) {
//        if (another instanceof BookBean){
//            BookBean anotherBook = (BookBean) another;
//            int result;
//
//            //比如这里按照书价排序
//            result = getCount() - anotherBook.getCount();     
//
//          //或者按照 String 的比较顺序
//          //result = getName().compareTo(anotherBook.getName());
//
//            if (result == 0){   //当书价一致时，再对比书名。 保证所有属性比较一遍
//                result = getName().compareTo(anotherBook.getName());
//            }
//            return result;
//        }
//        // 一样就返回 0
//        return 0;
//    }
//上述代码还重写了 equlas(), hashCode() 方法，自定义的类想要进行比较时都要重写这些方法。
//
//后面重写 compareTo 时，要判断某个相同时对比下一个属性，把所有属性都比较一次。
//
//Comparable 接口属于 Java 集合框架的一部分。
//
//Comparator 定制排序
//Comparator 在 java.util 包下，也是一个接口，JDK 1.8 以前只有两个方法：
//
//public interface Comparator<T> {
//
//    public int compare(T lhs, T rhs);
//
//    public boolean equals(Object object);
//}
//JDK 1.8 以后又新增了很多方法：
//
//
//基本上都是跟 Function 相关的，这里暂不介绍 1.8 新增的。
//
//从上面内容可知使用自然排序需要类实现 Comparable，并且在内部重写 comparaTo 方法。
//
//而 Comparator 则是在外部制定排序规则，然后作为排序策略参数传递给某些类，比如 Collections.sort(), Arrays.sort(), 或者一些内部有序的集合（比如 SortedSet，SortedMap 等）。
//
//使用方式主要分三步：
//
//创建一个 Comparator 接口的实现类，并赋值给一个对象
//在 compare 方法中针对自定义类写排序规则
//将 Comparator 对象作为参数传递给 排序类的某个方法
//向排序类中添加 compare 方法中使用的自定义类
//举个例子：
//
//        // 1.创建一个实现 Comparator 接口的对象
//        Comparator comparator = new Comparator() {
//            @Override
//            public int compare(Object object1, Object object2) {
//                if (object1 instanceof NewBookBean && object2 instanceof NewBookBean){
//                    NewBookBean newBookBean = (NewBookBean) object1;
//                    NewBookBean newBookBean1 = (NewBookBean) object2;
//                    //具体比较方法参照 自然排序的 compareTo 方法，这里只举个栗子
//                    return newBookBean.getCount() - newBookBean1.getCount();
//                }
//                return 0;
//            }
//        };
//
//        //2.将此对象作为形参传递给 TreeSet 的构造器中
//        TreeSet treeSet = new TreeSet(comparator);
//
//        //3.向 TreeSet 中添加 步骤 1 中 compare 方法中设计的类的对象
//        treeSet.add(new NewBookBean("A",34));
//        treeSet.add(new NewBookBean("S",1));
//        treeSet.add( new NewBookBean("V",46));
//        treeSet.add( new NewBookBean("Q",26));
//其实可以看到，Comparator 的使用是一种策略模式，不熟悉策略模式的同学可以点这里查看： 策略模式：网络小说的固定套路 了解。
//
//排序类中持有一个 Comparator 接口的引用：
//
//Comparator<? super K> comparator;
//而我们可以传入各种自定义排序规则的 Comparator 实现类，对同样的类制定不同的排序策略。
//
//总结
//Java 中的两种排序方式：
//
//Comparable 自然排序。（实体类实现）
//Comparator 是定制排序。（无法修改实体类时，直接在调用方创建）
//同时存在时采用 Comparator（定制排序）的规则进行比较。
//
//对于一些普通的数据类型（比如 String, Integer, Double…），它们默认实现了Comparable 接口，实现了 compareTo 方法，我们可以直接使用。
//
//而对于一些自定义类，它们可能在不同情况下需要实现不同的比较策略，我们可以新创建 Comparator 接口，然后使用特定的 Comparator 实现进行比较。
//
//这就是 Comparable 和 Comparator 的区别。

//《Java之Comparable，Comparator》

/*import java.util.Arrays;

//public class User implements Comparable<User> {
public class Comparable和Comparator implements Comparable<Comparable和Comparator> {
	private String id;
	private int age;

	public Comparable和Comparator(String id, int age) {
		this.id = id;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	@Override
	public int compareTo(Comparable和Comparator u) {
		return this.age - u.getAge();
	}

	public static void main(String[] args) {
		
		Comparable和Comparator[] users = new Comparable和Comparator[] { new Comparable和Comparator("a", 30), new Comparable和Comparator("b", 20) };
		//源码中可以看到调用了compareTo方法进行比较
		Arrays.sort(users);//从小到达排列
		
		//输出   b 20    a 30
		for (int i = 0; i < users.length; i++) {
			Comparable和Comparator user = users[i];
			System.out.println(user.getId() + " " + user.getAge());
		}
	}
}*/

/*import java.util.Arrays;
import java.util.Comparator;

//强行对某个对象collection进行整体排序的比较函数，
//可以将Comparator传递给Collections.sort或Arrays.sort。
public class Comparable和Comparator implements Comparator<String> {
//public class ComparatorDemo implements Comparator<String> {

	// 如果继承的是Comparator，则compare的两个方法是Object类型的
	@Override
	public int compare(String o1, String o2) {
		// 比较String的大小即可
		return toInt(o1) - toInt(o2);
	}

	private int toInt(String str) {
		//String str = (String) str;
		str = str.replaceAll("一", "1");
		str = str.replaceAll("二", "2");
		str = str.replaceAll("三", "3");
		return Integer.parseInt(str);
	}

	public static void main(String[] args) {
		String[] array = new String[] { "一二", "三", "二" };
		// 查看其源码，可以看到其是通过调用ComparatorDemo的compare方法比较大小的
		// 两个参数则为array里面的值
		Arrays.sort(array, new Comparable和Comparator());  //有小到达排列
		//最后输出     二      三     一二
		for (int i = 0; i < array.length; i++) {
			System.out.println(array[i]);
		}
		//可以尝试下面的方法
		//Collections.sort(list, c);
		
	}

}*/

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

//public class UserComparator implements Comparator<User> {
public class Comparable和Comparator implements Comparator<User> {

	@Override
	public int compare(User o1, User o2) {
		return o1.getAge() - o2.getAge();// 默认升序排列
	}

	public static void main(String[] args) {
		User[] users = new User[] { new User("a", 30), new User("b", 20),new User("x", 10) };
		// 运用UserComparator的compare方法进行比较:
		Arrays.sort(users, new Comparable和Comparator());
		// 输出 b 20 a 30
		for (int i = 0; i < users.length; i++) {
			User user = users[i];
			System.out.println("运用UserComparator的compare方法进行比较:"+user.getId() + " " + user.getAge());
		}

		List<User> list = new ArrayList<User>();
		list.add(new User("a", 30));
		list.add(new User("b", 20));
		list.add(new User("x", 10));
		// 内部转化成数组进行比较
		Collections.sort(list);// 运用User实现的compareTo方法进行比较
		// 输出 b 20 a 30
		for (int i = 0; i < list.size(); i++) {
			User user = list.get(i);
			System.out.println("运用User实现的compareTo方法进行比较:"+user.getId() + " " + user.getAge());
		}

		List<User> list2 = new ArrayList<User>();
		list2.add(new User("a", 30));
		list2.add(new User("b", 20));
		list2.add(new User("x", 10));
		Collections.sort(list2, new Comparable和Comparator());
		// 输出 b 20 a 30
		for (int i = 0; i < list2.size(); i++) {
			User user = list2.get(i);
			System.out.println("运用UserComparator的compare方法进行比较:"+user.getId() + " " + user.getAge());
		}
	}
}

class User implements Comparable<User>{
	private String id;
	private int age;

	public User(String id, int age) {
		this.id = id;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
	@Override
	public int compareTo(User o) {
		return o.getAge()-this.age;
	}
}